#!/bin/bash
#THIS DRIVER WRITTEN BY MATTHEW VONA ARB FOR THE TECO MODEL 43i-TLE 
#FOR QUESTIONS WRITE mailto:mvona@arb.ca.gov
#THIS DRIVER IS DEPENDENT UPON THE 'erec' COMMAND OF THE
#TECO RS232 INTERFACE.  WE USED THE DEFAULT CONFIGURATION
#BUT THIS CAN BE MODIFIED.
#UPDATED  9 Jun 2010 - by M McKay
#UPDATE May 14 2012 - by M Vona
#UPDATE - MODIFIED TO NOT CAUSE CARBLOGGER FREEZE IN THE EVENT THAT A STOP IN
#COMMUNICATION IS CAUSED. 10/20/2012
#UPDATE - A REALTIME INGEST COMPONENT WAS ADDED TO THIS DRIVER FOR FORWARD COMPATIBILITY WITH
#THE SUNRISE TECHNOLOGIES & QUOK GUI INTERFACE COMPATIBILITY -- MVONA
#ADDED PLOTTING CAPABILITIY, REMOVED REAL TIME INGEST -- MVONA
#-------------------------------------------------------------
# THIS IS THE FUNCTION CALLED IN THE EVENT THAT CTRL+C IS PRESSED
cleanup()
{
    echo "Caught Signal ... cleaning up."
        if !(rm -f Data/.locked > /dev/null); then
                {
                     exit 1
                }
        fi
for i in `pgrep -P ${plotterid}`;
	do
		kill -9 ${i} 2>/dev/null
	done
    	kill -9 ${plotterid} 2>/dev/null
    echo "Done cleanup ... quitting."
    exit 0
}
###############################################################
# BEGIN DISPLAY FUNCTION : MJV 11/15/2013                         #
###############################################################
#THIS IS THE RELATIVE DIRECTORY VARIABLE 
DIR="$( cd -P "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
#########################################################################################
#                       BEGIN MAIN DISPLAY FUNCTION.                                    #
#########################################################################################
#read config file
while read line; do
    eval $line
done < Config/config
if [[ -z "$no_plots" ]]; then
    {
        bash resources/TECO43iTLE_drv/plotter.sh 1>/dev/null 2>/dev/null &
        plotterid="$!"
    }
fi


#THE DIAGNOSTIC DATA (DIAG) ROUTINE TAKES THE DATA STREAM FROM THE TECO 43I-TLE
#AND TESTS FOR THE RECOGNITION OF KEY WORDS IN EACH LINE OF OUTPUT.
#IF THE KEY WORD IS DETECTED ON THAT LINE, A TEST IS PERFORMED. 
#IF THE TEST SUGGESTS THAT AN ERROR CONDITION EXISTS BASED UPON THE ALLOWABLE
#RANGES SPECIFIED BY THE ARB CHECKSHEET, THE OFFENDING LINE IS WRITTEN OUT 
#TO A FILE IN THE Data DIRECTORY. THE NAME OF THE DESTINATION FILE IS
#errors{HH}. THE FILES CAN THEN BE PARSED AND UTILIZED BY ANY ALERT PROGRAM?DAEMON.
diag()
{
this_name=$(cat ${DIR}/.usr$instance | grep -o "\-r [A-Za-z0-9]*" | awk '{ print $2 }')
thishour=`date "+%H"`
thisalert="errors${thishour}"
while read DIAGS
do
echo $DIAGS | awk -v name=$this_name '
{                                           
# TEST THE TIME AGAINST DATA LOGGER
if ($1 ~ /Date:/)
   	{
	if (substr($2,4,2)+0 == 23 )  
   		{
   		#test for off an hour or more
   		if (substr($2,1,2) != substr($1,length($1)-12,2))
   		{ print name" Time off by more than an hour! "$0 }
   		#test for off more than 3 minutes. Must add one minute to the 
   		#current minute value since the buffer contains values from the previous minute
   		if (sqrt(((substr($2,4,2)+1) - substr($1,length($1)-9,2))^2) > 4 )
   		{ print name " Time off by more than 2 minutes. " $0 }
   		}
   	}
# Set up Parameter Tests here for alarms
# TEST THE Sample Flow Rate
if ($1 ~ /Smpfl/ ) 
	{
 	if ( ($2+0) < 0.35)
  		{ print name " Sample flow seems low: " $0}
	if ( ($2+0) > 0.75)
  		{ print name " Sample flow seems high: " $0}
	}
#CHECK OPERATING TEMPERATURE
if ($1 ~ /Intt/ )
		{
		if ( ($2+0) < 15)
				{ print name " The Operating Temp is low: " $0}
		if ( ($2+0) > 45)
				{ print name " The Operating Temp is High: " $0}
		}			
# Check reaction chamber temperature
if ($1 ~ /Rctt/ )
                {
                if ( ($2+0) < 43)
                                { print name " Reaction Chamber Temp is low: " $0}
                if ( ($2+0) > 47)
                                { print name " Reaction Chamber Temp is High: " $0}
                }
#CHECK PRESSURE
if ($1 ~ /Pres/ )
                {
                if ( ($2+0) < 400)
                                { print name " Pressure is low: " $0}
                if ( ($2+0) > 1000)
                                { print name " Pressure is High: " $0}
                }


#CHECK PMT Voltage 
if ($1 ~ /pmtv/ )
                {
                if ( ($2+0) < -800)
                                { print name " The PMT Voltage is low: " $0}
                if ( ($2+0) > -600)
                                { print name " The PMT Voltage is High: " $0}
                }


#CHECK Flash lamp Voltage 
if ($1 ~ /lmpv/ )
                {
                if ( ($2+0) < 950)
                                { print name " Flash lamp voltage is low: " $0}
                if ( ($2+0) > 1200)
                                { print name " Flash lamp voltage is High: " $0}
                }

#CHECK Flash lamp reference 
if ($1 ~ /Lmpi/ )
                {
                if ( ($2+0) < 40)
                                { print name " Flash lamp reference is low: " $0}
                if ( ($2+0) > 100)
                                { print name " Flash lamp reference is High: " $0}
                }

		
}' >> "Data/$thisalert"
done
}
#BEGIN WRITE
#THIS FUNCTION HANDELS READ RIGHT HANDSHAKES BETWEEN VARIOUS DRIVERS
#IN GENERAL, THE DATA IS PLACED IN THE VARIABLE $TIMESTAMP PRIOR TO CALL
#NEXT, IT OPENS THE DATA DIRECTORY AND LOOKS FOR THE .locked FILE
#IF IT EXISTS, IT HANGS OUT UNTIL IT DOESN'T EXIST. AT THAT POINT
#IT CREATES A .locked FILE, AND APPENDS TO THE DATA RECORD.
#FINALLY IT REMOVES THE .locked FILE IT HAS CREATED.
#written by MJV
write()
{
#CONFIRM THAT THERE IS NO HIDDEN FILE CALLED '.locked'
	#PARSE THE .disabled File
        #IF THE FILE DOSEN'T EXIT OR IS NOT ACCESIBLE
        #MAKES SURE A VALUE OF 0 IS USED

	while read data
 	do
 	 {      
		#PARSE THE .disabled File
        channel_status=`cat ${DIR}/.disabled$instance`
        #IF THE FILE DOSEN'T EXIT OR IS NOT ACCESIBLE
        #MAKES SURE A VALUE OF 0 IS USED
		while [ -f Data/.locked ]
		do
		 sleep .1
		done
		#GENERATE THE LOCK FILE
		echo -n "1" > "Data/.locked";
	
	
	 case `expr $channel_status + 0` in
	 	"1" ) 
        	if !(echo "$data" | sed 's/^/'$timestamp'/g'| sed 's/$/'\ \-\-OFFLINE\-\-'/g'| tee -a "Data/$datafile" | diag); then
        	{
        		echo "GENERAL FAILURE WRITING TO RECORD: $#";
        		cleanup;
       	 	}
        	fi
        	;;
        "2" ) 
        	if !(echo "$data" | sed 's/^/'$timestamp'/g'| sed 's/$/'\ \-\-MAINTENANCE\-\-'/g'| tee -a "Data/$datafile" | diag); then
        	{
        		echo "GENERAL FAILURE WRITING TO RECORD: $#";
        		cleanup;
       	 	}
        	fi
        	;;	
        "3" ) 
        	if !(echo "$data" | sed 's/^/'$timestamp'/g'| sed 's/$/'\ \-\-REPAIR\-\-'/g'| tee -a "Data/$datafile" | diag); then
        	{
        		echo "GENERAL FAILURE WRITING TO RECORD: $#";
        		cleanup;
       	 	}
        	fi
        	;;
        "4" ) 
        	if !(echo "$data" | sed 's/^/'$timestamp'/g'| sed 's/$/'\ \-\-CALIBRATION\-\-'/g'| tee -a "Data/$datafile" | diag); then
        	{
        		echo "GENERAL FAILURE WRITING TO RECORD: $#";
        		cleanup;
       	 	}
        	fi
        	;;
        "5" ) 
        	if !(echo "$data" | sed 's/^/'$timestamp'/g'| sed 's/$/'\ \-\-AUDIT\-\-'/g'| tee -a "Data/$datafile" | diag); then
        	{
        		echo "GENERAL FAILURE WRITING TO RECORD: $#";
        		cleanup;
       	 	}
        	fi
        	;;
        "6" ) 
        	if !(echo "$data" | sed 's/^/'$timestamp'/g'| sed 's/$/'\ \-\-ZERO\-\-'/g'| tee -a "Data/$datafile" | diag); then
        	{
        		echo "GENERAL FAILURE WRITING TO RECORD: $#";
        		cleanup;
       	 	}
        	fi
        	;;
       	"0" )
			if !(echo "$data" | sed 's/^/'$timestamp'/g'| tee -a "Data/$datafile" | diag ); then
			{
				echo "GENERAL FAILURE WRITING TO RECORD: $#";
				cleanup;
			}
			fi
			;;	
	  esac
		
		if !(timestamp="" && data=""); then
		{
			echo "GENERAL FAILURE CLEARING WRITE BUFFER: $#";
			exit 1;
		}
		fi	
		if !(rm -f "Data/.locked" &> /dev/null); then
		{
			echo "GENERAL FAILURE REMOVING LOCK: $#" | logger;
			exit 1;	
		}
		fi   	
	}
  	done
}

#THIS IS THE ACTUAL COMMUNICATION WITH THE INSTRUMENT
#THE TIMER CONTROL. AT THE BEGINING IT TESTS FOR THE 
#EXISTENCE IF TOGGLE VARRIABLES WHICH ARE UTILIZED BOTH BY
#THE COMM ROUTINE runit() AND THE DIAGNOSTICS DATA ROUTINE
#diag()
runit()
{
#IF THE -d, -C, or -p variable is set to on, then append those parameters
#to the sjinn communication string. 
if [ "$p8n1_val" = "on" ]; then
 	p8n1="-p8n1"
fi
today=`date "+%Y-%d-%m"`
timestamp=$rprt_nm::`date "+%m-%d-%Y_%H:%M"`:::
#THIS IS THE NAME OF THE DATA FILE RIGHT NOW
datafile="$saroad-$today"
#TALK TO THE INSTRUMENT, PRE-APPEND THE TIMESTAMP AND REPORTING NAME TO EACH
#LINE OF OUTPUT AND tee TO THE DATA FILE, then pass to the diag routine.
data_raw=`timeout 10 sjinn -b$bd_rt -d $dvc_prt -s "$cmnd1" -r$rsp_lngth -w$wt_rsp1 $p8n1`
	echo $data_raw | grep -o "[0-2][0-9]\:[0-9][0-9]\ [0-9]*\-[0-9]*\-[0-9]*" | sed 's/^/Date: /g'>.${$}
	#echo $data_raw | grep -o "[0-9]\ so2\ [-,.,0-9]*" | awk '{ print $2" "$3 }' >> .${$}
	#echo $data_raw | grep -o "[0-9]\ so2\ [-,.,0-9]*\ intt" | awk '{ print $2" "$3 }' | sed 's/so2 /TLE_so2=/' >> .${$}
	echo $data_raw | grep -o "flags\ [0-9][A-Z][0-9]*" >> .${$}
	echo $data_raw | grep -o "Intt\ [-,.,0-9]*" >> .${$}
	echo $data_raw | grep -o "rctt\ [-,.,0-9]*" >> .${$}
	echo $data_raw | grep -o "Pres\ [-,.,0-9]*" >> .${$}
	echo $data_raw | grep -o "Smpfl\ [-,.,0-9]*" >> .${$}
	echo $data_raw | grep -o "pmtv\ [-,.,0-9]*" >> .${$}
	echo $data_raw | grep -o "lmpv\ [-,.,0-9]*" >> .${$}
	echo $data_raw | grep -o "Lmpi\ [-,.,0-9]*" >> .${$}
	echo $data_raw | grep -o "sum\ [-,.,0-9]*" >> .${$}
	echo $data_raw | grep -o "lo SO2\ coef\ [-,.,0-9]*" >> .${$}
	echo $data_raw | grep -o "so2\ bkg\ [-,.,0-9]*" >> .${$}
	echo $data_raw | grep -o "\ loso2\ [-,.,0-9]*" | sed 's/ loso2 / TLE_so2=/' >> .${$}
	echo $data_raw | grep -o "lo\ SO2\ coef\ [-,.,0-9]*" | awk '{ print $3" "$4  }' >> .${$}
	echo $data_raw | grep -o "SO2bkg\ [-,.,0-9]*" | awk '{ print $1" "$2 }' >> .${$}
	#IF DISCONNECTED THEN CHENGE THIS TO -999
	less_period=`echo ${data_raw} | tr -d \.`	
	length_less_period=${#less_period}
	if [[ $length_less_period == 0 ]]; then
		{ 
			echo 'TLE_so2=-999.0' > .${$}
			errors_hour=`date "+%H"`
			#echo "${timestamp} has lost its connection this minute. Be sure to check DMS!" >> "Data/errors${errors_hour}"		
		}
	fi
	}
#THIS IS THE FUNCTION RUN IN THE EVENT THAT THE REQUIRED PARAMETERS
#ARE NOT ENTERED.
usage()
{
clear
cat << EOF
usage: $0 options
# THIS DRIVER WRITTEN BY MATTHEW VONA ARB FOR THE TECO 43itle SO2 analyzer
# Part Number 103259-00; S/N 0630518483
#FOR QUESTIONS WRITE mailto:mvona@arb.ca.gov
usage: $0 options
The following conditions will cause an entry to be made in a
../../Data/errors[HH] file, where HH stands for the two digit hour. The
'Entry' is simply the offending data received from the instrument.:

	+ TIME (PST) - If off by more than 2 minutes from the data logger
			or more than one hour.
	+ SAMPLE FL -  Less than .4 lpm or greater than .5 lpm 
	+ Intt -       Less than 20 or greater than 30
	+ cflow	-      Converter/Filter flow Less than 0.7 LPM or greater than 0.8 LPM

OPTIONS:
-h	display help
-r	rprt_nm [rn] (Do not include quotes)
-d	dvc_prt [eg, /dev/ttyS0, /dev/ttyUSB1] 
-b	bd_rt [2400,4800,9600,etc.]
-c	cmnd1 (e.g, lrec\\r)
-w	wt_rsp1 [seconds]
-l	rsp_lngth [characters]
-s	SAROAD number of the station
-t	[on/off] (OPTIONAL)
-C	[on/off] (OPTIONAL)
-p	[on/off] (OPTIONAL)
-I	instance
Last updated 9/10/2009
EOF
}
#HELP FUNCTION GIVES BACKGROUND ON THIS DRIVER
help_me ()
{
clear
cat .help
exit 0
}
def_opts ()
{
clear
cat .options
}

##CLEAR ALL VARIABLES               
rprt_nm= ; dvc_prt= ; bd_rt= ; cmnd1= ; wt_rsp1= ; bd_rt= ; rsp_lngth= ; izs_val= ;
dvc_prt= ; frqncy= ; dtr= ; ctr= ; p8n1= ; saroad= ; p8n1= ; id_nmbr= ; instance=1 ; 
##INITIALIZE THE BUFFER
return='NOT WRITTEN TO'
##loop through all variables and parameters
##Note that the position of the colon indicates the presence
##of a parameter to collect. The h parameter simply
##returns the help message.

while getopts “hr:s:d:b:c:w:l:f:t:I:p:” OPTION
do
	case $OPTION in
		U)
		upp_flow=$OPTARG
		;;
		L)
		low_flow=$OPTARG
		;;
		s)
		saroad=$OPTARG
		;;
		r)
		rprt_nm=$OPTARG
		;;
		d)
		dvc_prt=$OPTARG
		;;
		b)
		bd_rt=$OPTARG
		;;
		c)
		cmnd1=$OPTARG
		;;
		w)
		wt_rsp1=$OPTARG
		;;
		l)
		rsp_lngth=$OPTARG
		;;
		t)
		dtr_val=$OPTARG
		;;
		p)
		p8n1_val=$OPTARG
		;;
		I)
		instance=$OPTARG
		;;
		h)
		help_me
		exit 1
		;;
		*)
		usage
		exit 1
		;;
	esac
done
#CHECK FOR THE CRITICAL PARAMETERS, IF THEY ARE NOT PRESENT THEN
#RUN THE USAGE FUNCTION WHICH RETURNS THE INSTRUCTIONS FOR PROPER USAGE
#MUST HAVE r n d b c w l s
if [ -z "$rprt_nm" ] || [ -z "$dvc_prt" ] || [ -z "$bd_rt" ] || [ -z "$cmnd1" ] ||
[ -z "$wt_rsp1" ] || [ -z "$rsp_lngth" ] || [ -z "$saroad" ]
	then
		{
		usage
		exit
		}
fi
if [ -z "$instance" ]
then
	{
		echo "This driver must be launched from 1.0 or later. A value for instance was not passed."
	}
fi 
	#INITIALIZED THE RAN VARIABLE. THIS IS USED TO TOGGLE THE TIMER GATE
ran=0
	#TRAP CTRL+C
trap cleanup 1 2 3 6 15
	#SETUP THE OPERATING LOOP
while :
do
	#SET THE SECOND VARIABLE AS THE SECOND VALUE FROM THE DATA STAMP 
second=`date "+%S"`
	#IF THE SECOND VALUE IS LESS THAN 02, BEGIN RUNNING
if [ "$second" -eq "00" ] && [ "$ran" -eq "0" ]; then
	
		#RUN THE RUNIT FUNCTION
			runit
		#RUNIT CREATES A HIDDEN FILE CONTAINING THE TRANSCRIPT OF THE CONVERSATION WITH
		#THE INSTRUMENT. THE NAME OF THE FILE IS THE PROCESS ID OR ".${$}" THIS FILE
		#IS THEN FED TO THE WRITE FUNCTION. IT IS IMPORTANT WITH TECO DRIVERS 
		#THAT runit() RUNS EXACTLY AT THE TOP OF THE MINUTE, INDEPENDENT OF THE WRITE FUNCTION.
			write < .${$}
		#TOGGLE THE RAN VARIABLE SO THAT THE PROCESS WILL NOT REPEAT			
			ran=1
		#WAIT FOR COMPLETION OF THE RUNIT FUNCTION AND THE VARIABLE
		#SET
			sleep 2
else 
	
		#WAIT ONE SECOND
			sleep .2
		#SET RAN TO 0
			ran=0
	
fi
done;
exit;

